package com.haiyou.mini.programs.wxpay;

import com.haiyou.mini.programs.config.WxMiniConfig;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;

/**
 * 2018/7/3
 */
@Slf4j
public final class WxPayXmlUtil {
    public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        documentBuilderFactory.setXIncludeAware(false);
        documentBuilderFactory.setExpandEntityReferences(false);

        return documentBuilderFactory.newDocumentBuilder();
    }

    public static Document newDocument() throws ParserConfigurationException {
        return newDocumentBuilder().newDocument();
    }

    /**
     * 响应微信支付消息
     *
     * @param payStatus
     * @param payMessage
     * @param response
     * @throws IOException
     */
    public static void sendWxNoticeMessage(String payStatus, String payMessage, HttpServletResponse response) {
        try {
            String resXml = "<xml><return_code><![CDATA[%s]]></return_code><return_msg><![CDATA[%s]]></return_msg></xml> ";
            resXml = String.format(resXml, payStatus, payMessage);
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param wxPayConfig
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public static Map<String, String> checkNotify(WxMiniConfig wxPayConfig, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //读取参数
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        //sb为微信返回的xml
        String notifyData = sb.toString();
        //支付结果通知的xml格式数据
        log.info("---->支付结果通知的xml格式数据：{}", notifyData);

        WxPay wxpay = new WxPay(wxPayConfig);
        Map<String, String> notifyMap = WxPayUtil.xmlToMap(notifyData);
        log.info("--------->回调参数：{}", notifyMap);

        if (!wxpay.isPayResultNotifySignatureValid(notifyMap)) {
            // 签名错误，如果数据里没有sign字段，也认为是签名错误
            log.error("---->通知签名验证失败");
            WxPayXmlUtil.sendWxNoticeMessage("FAIL", "通知签名验证失败", response);
            throw new RuntimeException("通知签名验证失败");
        }

        if (!"SUCCESS".equals(notifyMap.get("result_code"))) {
            log.info("------->支付失败,错误信息：{}", notifyMap.get("err_code"));
            WxPayXmlUtil.sendWxNoticeMessage("FAIL", "报文为空", response);
            throw new RuntimeException("支付失败");
        }
        return notifyMap;
    }

}
